/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.pp.services;

import com.pp.entites.Evenement;
import com.pp.entites.EvenementPK;
import com.pp.entites.Mobiledevice;
import com.pp.entites.MobiledeviceHasEvenement;
import com.pp.entites.MobiledeviceHasEvenementPK;
import com.pp.entites.Tube;
import com.pp.persistance.EvenementJpaController;
import com.pp.persistance.MobiledeviceHasEvenementJpaController;
import com.pp.persistance.MobiledeviceJpaController;
import com.pp.persistance.TubeJpaController;
import java.util.ArrayList;
import java.util.GregorianCalendar;
import java.util.List;
import javax.annotation.Resource;
import javax.ejb.EJBContext;
import javax.ejb.Stateless;
import javax.ejb.TransactionManagement;
import javax.ejb.TransactionManagementType;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceContext;
import javax.transaction.UserTransaction;

/**
 *
 * @author arnaud
 */
@Stateless
@TransactionManagement(TransactionManagementType.BEAN)
public class Evenement_ejb implements Evenement_ejbLocal {
    @Resource
    private EJBContext context;

     @PersistenceContext(unitName="ppSystLocal_EnterpriseApp-ejbPU")
     private EntityManager em ;
     
     private  EntityManagerFactory emf = null;
     private  UserTransaction utx = null;
        
     /**
      * retourne un evenement à partir de sa clef objet de type EvenementPK
      * @param idEvt
      * @return 
      */
    @Override
    public Evenement getEvenement(EvenementPK idEvt) {
        EntityManagerFactory emfa = getEntityManagerFactory();
        UserTransaction utxn = getUserTransaction();
        EvenementJpaController dao = new EvenementJpaController(utxn, emfa);

        return dao.findEvenement(idEvt);
    }
    
    /**
     * retourne un événement à parir de son idCreateur et de son numéro
     * @param idCreateur créateur de l'événement
     * @param numEvt numéro sequentiel de l'événement chez son créateur
     * @return 
     */
    @Override
    public Evenement getEvenement(String idCreateur, int numEvt) {
        EvenementPK cle = new EvenementPK(idCreateur, numEvt);
        return getEvenement(cle);
    }

    /**
     * integration d'un evenement venant d'etre envoyé sur le webservice entrant
     * l'evenement est "joué" (ses effets sont pris en compte)
     * puis il est inseré dans la table d'evenement 
     * ainsi que dans la table mobiledevice_has_evenement afin qu'il soit rediffusé
     * vers tous les mobiles
     * @param evtJson
     * @return 
     */
    @Override
    public Evenement IntegrationEvenement(String evtJson) {
        EntityManagerFactory emfa = getEntityManagerFactory();
        UserTransaction utxn = getUserTransaction();
        EvenementJpaController daoEvt = new EvenementJpaController(utxn, emfa);
        Evenement evt;
        try{
            evt = new Evenement(evtJson);
        }catch(Exception e){
System.out.println("EVENEMENT NULL");
            return null;
        }
        if(evt != null && daoEvt.findEvenement(evt.getEvenementPK()) != null){
System.out.println("EVENEMENT DEJA PRESENT");
            return evt;
        }
        try {
            // prise en compte des effets de l'événement
            runEvenement(evt);
            // persistance de l'événement
            daoEvt.create(evt);
            // mise a disposition de toutes les tablettes de cet événement
            insereEvenementDansMobiledeviceHasEvenement(evt); 
System.out.println("EVENEMENT INSERE : idCreateur="+evt.getEvenementPK().getIdCreateur()+"  num="+evt.getEvenementPK().getNumEvenement());
        } catch (Exception ex) {
System.out.println("ERREUR LORS DE L'INSERTION D'EVENEMENT");
            return null;
        }
        return evt;
    }
    /**
     * Methode permettant d'inserer un ligne correspondant à l'evenement recu pour chaque
     * mobile auquel il doit etre diffusé
     * @param evt
     * @throws Exception 
     */
    private void insereEvenementDansMobiledeviceHasEvenement(Evenement evt) throws Exception{
        EntityManagerFactory emfa = getEntityManagerFactory();
        UserTransaction utxn = getUserTransaction();
        MobiledeviceJpaController daoMobile = new MobiledeviceJpaController(utxn, emfa);
        MobiledeviceHasEvenementJpaController daoMobileEvt = new MobiledeviceHasEvenementJpaController(utxn, emfa);
        
        String idCreateur = evt.getEvenementPK().getIdCreateur();
        
        /* MaJ de la table MobileDeviceHasEvenement */
        //Recuperation de la liste des mobileDevices
        List<Mobiledevice> listMobiles = daoMobile.findMobiledeviceEntities();
        //pour chaque mobile
        for(Mobiledevice mobile : listMobiles){
            // on cree une entree dans mobiledeviceHasEvenement
            MobiledeviceHasEvenement mobileEvt = new MobiledeviceHasEvenement();
            mobileEvt.setEvenement(evt);            
            mobileEvt.setMobiledevice(mobile);
            mobileEvt.setADiffuser(Boolean.TRUE);
            if(idCreateur.equals(mobile.getId())){
                mobileEvt.setTimestampReception((new GregorianCalendar()).getTime());
            }
            mobile.addMobiledeviceHasEvenement(mobileEvt);
            daoMobileEvt.create(mobileEvt);
        }        
    }
    
    /**
     * methode permettant d'orienter vers la methode ad-hoc de prise en compte des effets
     * d'un evenement
     * @param evt
     * @throws Exception 
     */
    private void runEvenement(Evenement evt) throws Exception{
        switch(evt.getTypeEvenement()){
            case Evenement.CONTROLE_TUBE:   controleTube(evt);
                                            break;
        }
    }
    /**
     * methode de prise en compte d'un evenement de type controle de tube
     * @param evt
     * @throws Exception 
     */
    private void controleTube(Evenement evt) throws Exception{
        //Recuperation de l'id du tube
        String contenu = evt.getContenu();
        String[] tab = contenu.split(":");
        Long idTube = Long.parseLong(tab[1]);
        if(idTube != null){        
            EntityManagerFactory emfa = getEntityManagerFactory();
            UserTransaction utxn = getUserTransaction();
            // recuperation du tube
            TubeJpaController daoTube = new TubeJpaController(utxn, emfa);
            Tube tube = daoTube.findTube(idTube);
            //mise a jour du tube
            tube.setNbControles(tube.getNbControles()+1);
            //enregistrementMaJ
            daoTube.edit(tube);
        }else{
            throw new Exception();
        }
    }
    
    private  EntityManagerFactory getEntityManagerFactory(){
        if(this.emf==null)
            emf = em.getEntityManagerFactory();
        return emf;
    }
    private  UserTransaction getUserTransaction(){
        if(this.utx == null)
            utx = context.getUserTransaction();
        return utx;
    }

    /**
     * Retourne la liste des evenements devant etre envoyes à un mobile identifié
     * @param idMobile
     * @return 
     */
    @Override
    public List<EvenementPK> getListeEvtADiffuser(String idMobile) {
        EntityManagerFactory emfa = getEntityManagerFactory();
        UserTransaction utxn = getUserTransaction();
        // recupération des lignes de la table mobileDevice_has_evenement
        // concernées par le mobile et pour lesquelles l'événement est à diffuser
        MobiledeviceHasEvenementJpaController daoMobileEvt = new MobiledeviceHasEvenementJpaController(utxn, emfa);
        List<MobiledeviceHasEvenement> listeA = daoMobileEvt.findByIdmobileAndADiffuser(idMobile, true);
        if(listeA == null){
            return null;
        }
        List<EvenementPK> retour = new ArrayList<EvenementPK>();
        for(MobiledeviceHasEvenement m : listeA){
            retour.add(m.getEvenement().getEvenementPK());
        }
        return retour;
    }

    /**
     * Action effectuée lors de la réception d'un ACK de la part d'un mobile,
     * à l'occasion de la récupération d'un événement
     * Lorsque le service reçoit un ack d'un mobile, il peut considérer que
     * l'événement a bien été reçu et intégré dans la bdd du mobile
     * donc il peut le considéré comme diffusé pour ce mobile
     * @param idCreateur premiere partie de la clef primaire de l'événement
     * @param numEvenement seconde partie de la clef primaire de l'événement
     * @param idMobile clef primaire du mobile qui accuse réception de l'événement
     * @return true si la modification dans la bdd du serveur (evt diffusé) s'est bien passée
     */
    @Override
    public boolean ackDiffusionEvenementToMobile(String idCreateur, int numEvenement, String idMobile) {
        boolean retour = false;
        EntityManagerFactory emfa = getEntityManagerFactory();
        UserTransaction utxn = getUserTransaction();
        // récupération de la ligne de la table mobileDevice_has_evenement
        // correspondante à l'événement pour le mobile donné
        MobiledeviceHasEvenementJpaController daoMobileEvt = new MobiledeviceHasEvenementJpaController(utxn, emfa);
        MobiledeviceHasEvenementPK key = new MobiledeviceHasEvenementPK(idMobile, idCreateur, numEvenement);
        MobiledeviceHasEvenement mobileEvt = daoMobileEvt.findMobiledeviceHasEvenement(key);
        if(mobileEvt != null){
            // modification des champs
            mobileEvt.setADiffuser(false);
            mobileEvt.setTimestampDiffusion((new GregorianCalendar()).getTime());
            try {
                // persistance de la ligne
                daoMobileEvt.edit(mobileEvt);
                retour = true;
            } catch (Exception ex) {
                System.out.println("ERREUR PERSISTANCE LORS DE LA RECEPTION ACK DIFFUSION");
            }
        }
        return retour;
    }


    
    
    
}
